// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ****************************************************************************
//  File: SubsetViewerEnginePluginInfo.C
// ****************************************************************************

#include <SubsetPluginInfo.h>
#include <avtSubsetPlot.h>
#include <SubsetAttributes.h>

//
// Storage for static data elements.
//
SubsetAttributes *SubsetViewerEnginePluginInfo::clientAtts = NULL;
SubsetAttributes *SubsetViewerEnginePluginInfo::defaultAtts = NULL;

// ****************************************************************************
//  Method:  SubsetViewerEnginePluginInfo::InitializeGlobalObjects
//
//  Purpose:
//    Initialize the plot atts.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************
void
SubsetViewerEnginePluginInfo::InitializeGlobalObjects()
{
    if (SubsetViewerEnginePluginInfo::clientAtts == NULL)
    {
        SubsetViewerEnginePluginInfo::clientAtts  = new SubsetAttributes;
        SubsetViewerEnginePluginInfo::defaultAtts = new SubsetAttributes;
    }
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Return a pointer to the viewer client attributes.
//
//  Returns:    A pointer to the viewer client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
SubsetViewerEnginePluginInfo::GetClientAtts()
{
    return clientAtts;
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::GetDefaultAtts
//
//  Purpose:
//    Return a pointer to the viewer default attributes.
//
//  Returns:    A pointer to the viewer default attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
SubsetViewerEnginePluginInfo::GetDefaultAtts()
{
    return defaultAtts;
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::SetClientAtts
//
//  Purpose:
//    Set the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to the new client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
SubsetViewerEnginePluginInfo::SetClientAtts(AttributeSubject *atts)
{
    *clientAtts = *(SubsetAttributes *)atts;
    clientAtts->Notify();
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Get the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to return the client default attributes in.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
SubsetViewerEnginePluginInfo::GetClientAtts(AttributeSubject *atts)
{
    *(SubsetAttributes *)atts = *clientAtts;
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::AllocAvtPlot
//
//  Purpose:
//    Return a pointer to a newly allocated avt plot.
//
//  Returns:    A pointer to the newly allocated avt plot.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

avtPlot *
SubsetViewerEnginePluginInfo::AllocAvtPlot()
{
    return new avtSubsetPlot;
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::InitializePlotAtts
//
//  Purpose:
//    Initialize the plot attributes to the default attributes.
//
//  Arguments:
//    atts      The attribute subject to initialize.
//
//  Programmer: whitlocb -- generated by xml2info
//  Creation:   Tue Mar 18 09:01:21 PDT 2003
//
//  Modifications:
//    Kathleen Bonnell, Tue Nov  6 08:19:45 PST 2001
//    Create labels only from mesh related to varName, not from all
//    meshes.
//
//    Hank Childs, Wed Aug 14 11:30:18 PDT 2002
//    Only use the labels from the material we actually have.
//
//    Kathleen Bonnell, Thu Sep  5 10:55:47 PDT 2002
//    Moved bulk of code to PrivateSetPlotAtts to aid in maintenance, as it is
//    shared with ResetPlotAtts.
//
//    Brad Whitlock, Fri Mar 26 15:22:11 PST 2004
//    I made it use passed in metadata.
//
//    Brad Whitlock, Wed Feb 21 14:31:20 PST 2007
//    Changed API.
//
// ****************************************************************************

void
SubsetViewerEnginePluginInfo::InitializePlotAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)
{
    *(SubsetAttributes*)atts = *defaultAtts;

    PrivateSetPlotAtts(atts, plot);
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::ReInitializePlotAtts
//
//  Purpose:
//    ReInitialize the plot attributes.
//
//  Arguments:
//    atts      The attribute subject to initialize.
//
//  Programmer: Kathleen Bonnell
//  Creation:   December 5, 2002
//
//  Modifications:
//    Brad Whitlock, Fri Mar 26 15:22:11 PST 2004
//    I made it use passed in metadata.
//
//    Brad Whitlock, Wed Feb 21 14:31:20 PST 2007
//    Changed API.
//
// ****************************************************************************

void
SubsetViewerEnginePluginInfo::ReInitializePlotAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)
{
    PrivateSetPlotAtts(atts, plot);
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::ResetPlotAtts
//
//  Purpose:
//    Initialize the plot attributes to the default attributes.
//
//  Arguments:
//    atts      The attribute subject to initialize.
//
//  Programmer: meredith -- generated by xml2info
//  Creation:   Fri Sep 7 10:53:06 PDT 2001
//
//  Modifications:
//    Kathleen Bonnell, Mon Apr 29 13:37:14 PDT 2002
//    Create labels only from mesh related to varName, not from all
//    meshes.
//
//    Hank Childs, Wed Aug 14 11:30:18 PDT 2002
//    Only use the labels from the material we actually have.
//
//    Kathleen Bonnell, Thu Sep  5 10:55:47 PDT 2002
//    Moved code to PrivateSetPlotAtts to aid in maintenance, as the code is
//    shared with InitializePlotAtts.
//
//    Brad Whitlock, Fri Mar 26 15:22:11 PST 2004
//    I made it use passed in metadata.
//
//    Brad Whitlock, Wed Feb 21 14:31:20 PST 2007
//    Changed API.
//
// ****************************************************************************

void
SubsetViewerEnginePluginInfo::ResetPlotAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)

{
    PrivateSetPlotAtts(atts, plot);
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::GetMenuName
//
//  Purpose:
//    Return a pointer to the name to use in the viewer menus.
//
//  Returns:    A pointer to the name to use in the viewer menus.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

const char *
SubsetViewerEnginePluginInfo::GetMenuName() const
{
    return "Subset";
}

// ****************************************************************************
//  Method: SubsetViewerEnginePluginInfo::PrivateSetPlotAtts
//
//  Purpose:
//    Initialize the plot attributes.
//
//  Arguments:
//    atts          The attribute subject to initialize.
//    hostName      The host name of the plot.
//    databaseName  The database name of the plot.
//    varName       The variable name of the plot.
//
//  Notes:
//    This code was pulled from ResetPlotAtts and InitializePlotAtts to
//    aid in maintenance, and reworkd to support groups.
//
//  Programmer: Kathleen Bonnell
//  Creation:   September 5, 2002
//
//  Modifications:
//    Kathleen Bonnell, Thu Dec  5 16:53:22 PST 2002
//    Changed exception from ImproperUse to InvalidVariable.
//
//    Brad Whitlock, Wed Nov 20 14:12:03 PST 2002
//    I added support for discrete color tables.
//
//    Kathleen Bonnell, Thu Sep  4 16:08:46 PDT 2003
//    Set colors, subsetNames for defaultAtts so that "Reset" won't zero
//    out the colors in the gui.
//
//    Brad Whitlock, Fri Mar 26 15:22:11 PST 2004
//    I made it use passed in metadata.
//
//    Jeremy Meredith, Fri Aug 25 16:59:42 EDT 2006
//    Support enumerated scalar type subsets.
//
//    Brad Whitlock, Wed Feb 21 14:31:20 PST 2007
//    Changed API.
//
//    Jeremy Meredith, Wed Feb 13 14:57:31 EST 2008
//    Allowed meshes to pass through with a single category, even though
//    they are not a subset variable.
//
//    Jeremy Meredith, Mon Feb 23 17:43:55 EST 2009
//    Created a new subset type for meshes and used that.  (Apparently
//    I had left the type as EnumScalar before, which didn't cause any
//    problems at the time, but is obviously not quite correct.)
//
//    Hank Childs, Tue Dec 15 15:08:41 PST 2009
//    Add support for groups based on ranges.
//
//    Kathleen Biagas, Tue Aug 27 16:59:10 PDT 2013
//    Add support for groupNames.
//
//    Kathleen Biagas, Thu Dec 15 16:13:57 PST 2016
//    Removed Material as a subset option.
//
// ****************************************************************************
#include <stdio.h>

#include <avtColorTables.h>
#include <avtDatabaseMetaData.h>
#include <avtTypes.h>
#include <set>

#include <avtPlotMetaData.h>

#include <DebugStream.h>
#include <InvalidVariableException.h>

void
SubsetViewerEnginePluginInfo::PrivateSetPlotAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)
{
    SubsetAttributes *subsetAtts = (SubsetAttributes *)atts;

    //
    // Get the meta-data and initialize the subset names and colors in the
    // new SubsetAttributes object.
    //
    const avtDatabaseMetaData *md = plot.GetMetaData();
    if (md == NULL)
    {
        return;
    }

    avtDatabaseMetaData *nonConstmd = const_cast <avtDatabaseMetaData *>(md);

    std::string vn(plot.GetVariableName());

    const avtScalarMetaData *smd = NULL;

    std::string meshName = nonConstmd->MeshForVar(vn);
    avtMeshMetaData *mesh =
        const_cast <avtMeshMetaData *> (md->GetMesh(meshName));


    stringVector       sv;
    stringVector::const_iterator pos;
    std::set<int> groupSet;
    std::vector<int> gIDS;
    char temp[512];

    //
    // Create subset names, based on Subset Type
    //
    avtSubsetType subT = nonConstmd->DetermineSubsetType(vn);
    switch (subT)
    {
      case AVT_DOMAIN_SUBSET :
          debug5 << "Variable for subset plot is a domain Mesh." << endl;
          subsetAtts->SetSubsetType(SubsetAttributes::Domain);
          defaultAtts->SetSubsetType(SubsetAttributes::Domain);
          if (mesh->blockNames.empty())
          {
              for (int i = 0; i < mesh->numBlocks; i++)
              {
                  sprintf(temp, "%d", i+mesh->blockOrigin);
                  sv.push_back(temp);
              }
          }
          else
          {
              for(pos = mesh->blockNames.begin();
                  pos != mesh->blockNames.end(); ++pos)
              {
                  sv.push_back(*pos);
              }
          }
          break;

      case AVT_GROUP_SUBSET :
          debug5 << "Variable for subset plot is a group Mesh." << endl;
          subsetAtts->SetSubsetType(SubsetAttributes::Group);
          defaultAtts->SetSubsetType(SubsetAttributes::Group);
          if (!mesh->groupNames.empty())
          {
              for (size_t i = 0; i < mesh->groupNames.size(); ++i)
              {
                  sv.push_back(mesh->groupNames[i]);
              }
          }
          else if (mesh->groupIds.size() > 0)
          {
              for (size_t i = 0; i < mesh->groupIds.size(); i++)
              {
                  if (groupSet.count(mesh->groupIds[i]) == 0)
                  {
                      groupSet.insert(mesh->groupIds[i]);
                      gIDS.push_back(mesh->groupIds[i]);
                  }
              }
              for (size_t i = 0; i < gIDS.size(); i++)
              {
                  sprintf(temp, "%d", gIDS[i]);
                  sv.push_back(temp);
              }
          }
          else
          {
              int origin = mesh->groupOrigin;
              int nGroups = (int)mesh->groupIdsBasedOnRange.size()-1;
              for (int i = 0; i < nGroups; i++)
              {
                  groupSet.insert(origin+i);
                  gIDS.push_back(origin+i);
                  sprintf(temp, "%d", origin+i);
                  sv.push_back(temp);
              }
          }
          break;

      case AVT_ENUMSCALAR_SUBSET :
          debug5 << "Variable for subset plot is an enumerated Scalar."<<endl;
          subsetAtts->SetSubsetType(SubsetAttributes::EnumScalar);
          defaultAtts->SetSubsetType(SubsetAttributes::EnumScalar);
          smd = md->GetScalar(vn);
          if (smd != NULL)
          {
              for(pos = smd->enumNames.begin();
                  pos != smd->enumNames.end(); ++pos)
              {
                  sv.push_back(*pos);
              }
          }
          break;

      default:
          if (vn == meshName)
          {
              debug5 << "Variable for subset plot is a mesh."<<endl;
              subsetAtts->SetSubsetType(SubsetAttributes::Mesh);
              defaultAtts->SetSubsetType(SubsetAttributes::Mesh);
              sprintf(temp, "Whole mesh (%s)", vn.c_str());
              sv.push_back(temp);
          }
          else
          {
              EXCEPTION1(InvalidVariableException, vn);
          }
          break;
    }

    //
    // Add a color for each subset name.
    //
    ColorAttribute *ca = new ColorAttribute[sv.size() + 1];
    avtColorTables *ct = avtColorTables::Instance();
    if(ct->IsDiscrete(ct->GetDefaultDiscreteColorTable()))
    {
        // The CT is discrete, get its color color control points.
        for(size_t i = 0; i < sv.size(); ++i)
        {
            unsigned char rgb[3] = {0,0,0};
            ct->GetControlPointColor(ct->GetDefaultDiscreteColorTable(), (int)i, rgb);
            ca[i].SetRed(int(rgb[0]));
            ca[i].SetGreen(int(rgb[1]));
            ca[i].SetBlue(int(rgb[2]));
        }
    }
    else
    {
        // The CT is continuous, sample the CT so we have a unique color
        // for each element in sv.
        unsigned char *rgb = ct->GetSampledColors(
            ct->GetDefaultDiscreteColorTable(), (int)sv.size());
        if(rgb)
        {
            for(size_t i = 0; i < sv.size(); ++i)
            {
                ca[i].SetRed(int(rgb[i*3]));
                ca[i].SetGreen(int(rgb[i*3+1]));
                ca[i].SetBlue(int(rgb[i*3+2]));
            }
            delete [] rgb;
        }
    }

    ColorAttributeList cal;
    int idx = 0;
    for(pos = sv.begin(); pos != sv.end(); ++pos)
    {
        if (idx < subsetAtts->GetMultiColor().GetNumColors())
        {
            // The meshIndex is within the defaultAtts' color
            // vector size.
            cal.AddColors(subsetAtts->GetMultiColor()[idx]);
        }
        else
        {
            // The meshIndex is greater than the size of the
            // defaultAtts' color vector. Use colors from the
            // default discrete color table.
            cal.AddColors(ca[idx]);
        }
        ++idx;
    }

    delete [] ca;

    // Set the subset names and colors in the subsetAtts.
    subsetAtts->SetSubsetNames(sv);
    subsetAtts->SetMultiColor(cal);
    defaultAtts->SetSubsetNames(sv);
    defaultAtts->SetMultiColor(cal);
}

